<?

function dump($input,$key="...")
{
	$dump=new dump;
	$dump->data($input,$key);
	$dump->print_styled();
} 

function save_dump($input,$filename="var_dump.html",$return=false)
{
	$dump=new dump;
	$dump->data($input,$key);
	$link=$dump->save($filename);
	if($return){
		echo $link;
	}
} 

function search_dump($input,$search)
{
	$dump=new dump;
	$input=$dump->search($input,$search);
	$dump->data($input,$key);
	$dump->print_styled();	
}

function trace_dump()
{
	$dump=new dump;
	$dump->data(debug_backtrace(),$key);
	$dump->print_styled();
}

if(!empty($_REQUEST["img"])){
	header("Content-type: image/gif");
	switch ($_REQUEST["img"]) {
		case "minus.gif":
			echo base64_decode("R0lGODlhCgAKAIAAACAYJAAAACH5BAEAAAEALAAAAAAKAAoAAAINjI+pa+APo5wUsotPAQA7");
			break;
		
		case "plus.gif":
			echo base64_decode("R0lGODlhCgAKAIAAACAYJAAAACH5BAEAAAEALAAAAAAKAAoAAAISjIFgG6nc0nK02otfRHDrKRkFADs=");
			break;
			
		case "popup.gif":
			echo base64_decode("R0lGODlhCgAKAIAAACAYJAAAACH5BAEAAAEALAAAAAAKAAoAAAIRjI+pa+APDnxyxmYV1DRtUwAAOw==");
			break;
	}
}

/**
* Common Class to Dump data in an comprehensible fashion
*/
class dump
{
	var $template=array(
'ul'=>'
	<ul{class:ul}>
		{value:ul}
	</ul>',
'li'=>'
	<li{class:li}>
		<!--<a onClick="popup(this)" title="open this part in a new window" class="icon">&nbsp;</div>-->
		<a onClick="dumpToggle(this)" title="{value:title}">
			{value:a}
		</a>
		{sub}
	</li>',
'text'=>'
	<li{class:li}>
		<div class="overflow">
			{value:li}
		</div>
	</li>',
'value'=>'
	<span title="{info}"><strong>{key}</strong> <em>({type})</em> <var>{value}</var></span>',
'table'=>'
	<div class="overflow">
		<table cellspacing="0px" cellpadding="0">
			{value:table}
		</table>
	</div>',
'table:head:item'=>
	'<th {config:th}>
		{value:th}
	</th>',
'table:item'=>
	'<td {config:td}>
		{value:td}
	</td>',
'table:row:even'=>
	'<tr class="even" {config:tr}>
		{value:tr}
	</tr>',
'table:row:odd'=>
	'<tr class="odd" {config:tr}>
		{value:tr}
	</tr>');

	public function StyleAndJS($overwrite=false)
	{
		if(!defined("dumpStyleAndJS")||$overwrite){
			$this->StyleAndJS="<script type='text/javascript' charset='utf-8' id='dumpJS'>function dumpToggle(element) {
   var e = element.parentNode.getElementsByTagName('ul')[0];
   if(e!=null){
       if(e.style.display == 'block'){
          e.style.display = 'none';
    	  element.parentNode.style.backgroundImage='url(dump.inc.php?img=plus.gif)';
       }else{
          e.style.display = 'block';
    	  element.parentNode.style.backgroundImage='url(dump.inc.php?img=minus.gif)';
       }
    }
}
function popup(input) {
	var w=800;
	var h=700;
	
	x = screen.availWidth/2-w/2;
	y = screen.availHeight/2-h/2;
	var popup = window.open('','','width='+w+',height='+h+',left='+x+',top='+y+',screenX='+x+',screenY='+y+',resizable=yes,scrollbars=yes,toolbar=yes,status=>yes');
	
	var content=input.parentNode.parentNode;

	var head = popup.document.createElement('head');
	var body = popup.document.createElement('body');
	var html = popup.document.createElement('html');
	
  	var Script=document.getElementById('dumpJS');
  	var Style=document.getElementById('dumpStyle');
  	var StylePrint=document.getElementById('dumpStylePrint');
  	
  	head.appendChild(Script);
  	head.appendChild(Style);
  	head.appendChild(StylePrint);
  	
  	content.setAttribute('id','dump');
 	body.appendChild(content);
 	
 	html.appendChild(head);
 	html.appendChild(body);
 	
 	var newContent = html.innerHTML;
 	
 	popup.document.write(newContent);
 	popup.document.close();
}</script>";
			$this->StyleAndJS.="<style type='text/css' media='print' id='dumpStylePrint'>.dump ul{
	padding-left:22px;
	border-left: 1px dotted  #304860;
}
.dump{
	background:white;
	padding:2px;
	padding-left:22px;
	margin-right:10px;
	margin-left:10px;
	color:#1D2327;
	font-family:tahoma,Verdana;
	font-size:12px;
	display:block;
	border:1px #304860 solid;
}
.dump em{
	font-style:normal;
}
.dump var{
	font-style:normal;
	font-weight:bold;
}
.dump var{
	font-style:normal;
	font-weight:bold;
}
table{
	font-size:11px;
}
td{
	padding:2px;
	margin:0px;
}
th{
	padding:2px;
}</style>";
			$this->StyleAndJS.="<style type='text/css' media='screen' id='dumpStyle'>.dump li{
	color:#113C64;
}
.dump a{
	vertical-align:bottom;
	display:inline;
	width:100%;
	margin-left:5px;
}
.dump li,
.dump ul{
	list-style:none;
	margin:0px;
	cursor:text;
}
.dump li.hasSub{
	cursor:pointer;
	list-style:none;
	padding-left:10px;
	background: url(dump.inc.php?img=plus.gif) 0px 2px no-repeat;
}
.dump a:hover{
	background:#9ABBC7;
}
.dump ul{
	display:none;
	padding-left:22px;
	border-left: 1px dotted  #304860;
}
.dump{
	background:white;
	padding:4px;
	padding-left:22px;
	color:#1D2327;
	font-family:tahoma,Verdana;
	font-size:12px;
	display:block;
	border:1px #304860 solid;
}
.dump span.value{
	color:#113C64;
}
.dump em{
	font-style:normal;
}
.dump var{
	font-style:normal;
	font-weight:bold;
}
.dump var{
	font-style:normal;
	font-weight:bold;
}
/*
ul.array{
	background:#EEFF96;
	background:#E1FF4B;
}
ul.object{
	background:#DDDFFA;
}
ul.resource{
	background:#FFC4C3;
}*/
table{
	font-size:11px;
}
td{
	padding:2px;
	margin:0px;
}
th{
	padding:2px;
}
div.overflow{
	max-height:500px;
	overflow:auto;
}
/*
ul.resource:hover,
div.overflow:hover,
table:hover
{
	background:#FFC4C3;
}
tr.even td{
	background:#FFD4C3;
}
tr:hover td{
	background:#9ABBC7;
}
th{
	background:#eFa4a3;
}*/
.dump a.icon{
	height:10px;
	width:10px;
	display:inline;
	cursor:pointer;
	vertical-align:text-bottom;
	background: url(dump.inc.php?img=popup.gif) -1px 2px no-repeat;
}
span.toolbar{
	margin:0px;
	padding:0px;
	margin-left:20px;
}

.dump .text{
	background:#efefef;
}</style>";
			$this->return.=$this->StyleAndJS;
			define("dumpStyleAndJS",true);
		}
	}
	
	public function data($input,$key)
	{
		$this->StyleAndJS();
		$this->return.=$this->iterate($input,$key);
	}
	
	public function search($input,$search)
	{
		switch (TRUE) {
			case is_array($input):
				foreach ($input as $key => $value) {
					if(strpos($key,$search)!==FALSE){
						$return[$key]=$value;
					}else{
						$temp=$this->search($value,$search);
						if(!empty($temp)){
							$return[$key]=$temp;
						}
					}
				}
				return $return;
				break;
			
			case is_Object($input):
					
					break;	
			
			case is_Resource($input):
					
					break;	
				
			default:
				if(strpos($input,$search)!==FALSE){
					return $input;
				}
				break;
		}
	}
	
	public function recursionCheck(&$input)
	{
		switch (TRUE) {
			case is_array($input):
				foreach ($input as $key => $value) {
					if(is_array($value)){
						if(array_keys($input)==array_keys($value)){
							$input[$key]="Recursion";
						}
					}
				}
				break;
				
			default:
				break;
		}
	}
	
	public function iterate($inputValue,$inputKey)
	{	
		$this->recursionCheck($inputValue);
		
		if(empty($this->first)){
			$first=true;
			$this->first=1;
		}else{
			$first=false;
		}
		
		switch (!$first) {
			case FALSE:
				$first=false;
				$param=array(
					"class:ul"=>" class='dump ".gettype($inputValue)."'",
					"value:ul"=>$this->iterate($inputValue,$inputKey)
				);
				
				return $this->parse("ul",$param);
				break;
				
			case is_Array($inputValue):
				foreach ($inputValue as $key => $value) {
					$return.=$this->iterate($value,$key);
				}
				
				$param=array(
					"class:ul"=>" class='array'",
					"value:ul"=>$return
				);
				$return = $this->parse("ul",$param);
				
				
				$param["class:li"]=" class='hasSub'";
				$param["value:a"]=$this->getInfo($inputValue,$inputKey);
				$param["value:title"]=gettype($inputValue);
				$param["sub"]=$return;
				
				return $this->parse("li",$param);
				break;
			
			case is_Object($inputValue):
				$array=get_object_vars($inputValue);
				
				foreach ($array as $key => $value) {
					$return.=$this->iterate($value,$key);
				}
				
				$methods= get_class_methods($inputValue);
				
				foreach ($methods as $key => $value) {
					$return.=$this->iterate("method",$value);
				}
				
				$param=array(
					"class:ul"=>" class='object'",
					"value:ul"=>$return
				);
				$return = $this->parse("ul",$param);
				
				
				$param["class:li"]=" class='hasSub'";
				$param["value:a"]=$this->getInfo($inputValue,$inputKey);
				$param["value:title"]=gettype($inputValue);
				$param["sub"]=$return;
				
				return $this->parse("li",$param);
				break;
				
			case is_Resource($inputValue):
				switch (get_resource_type($inputValue)) {
					case 'mysql result':
						$param["value:a"]=$this->parseMysqlTable($inputValue);
						$param["value:title"]=gettype($inputValue);
						$return = $this->parse("li",$param);
						
						$param=array(
							"class:ul"=>" class='resource'",
							"value:ul"=>$return
						);
						$return = $this->parse("ul",$param);
						mysql_data_seek($inputValue,0);
						return $this->parseLi($this->getInfo($inputValue,$inputKey), $return,gettype($inputValue), " class='hasSub'");
						break;
					
					case 'mysql link':
						$param["value:a"]=$this->getInfo($inputValue,$inputKey);
						$param["value:title"]=gettype($inputValue);
						
						return $this->parse("li",$param);
						break;
					
					case 'stream':
						$metadata=stream_get_meta_data($inputValue);
						return $this->iterate($metadata,$inputKey);
						break;
						
					default:
						return get_resource_type($inputValue);
						break;
				}
				break;
				
			default:
				if(strlen($inputValue)>150){
					
					$return=$this->parseText($inputValue);
					
					$param=array(
						"class:ul"=>" class='text'",
						"value:ul"=>$return
					);
					$return = $this->parse("ul",$param);
					$param="";
					$param["class:li"]=" class='hasSub'";
				}
				
				$param["value:a"]=$this->getInfo($inputValue,$inputKey);
				$param["value:title"]=gettype($inputValue);
				$param["sub"]=$return;
				
				return $this->parse("li",$param);
				break;
		}
	}
	
	public function getInfo($input,$key){
		switch (TRUE) {
			case is_array($input):
				return $this->parseInfo($key,gettype($input).", ".count($input)." elements",$input);
				break;
				
			case is_object($input):
				return $this->parseInfo($key,gettype($input).", ".count(get_object_vars($input))." vars, ".count(get_class_methods($input))." methods",get_class($input));
				break;
			
			case ($input==="method"):
				return $this->parseInfo($key."()","method");
				break;
				
			case is_string($input):
				return $this->parseInfo($key,gettype($input).", ".strlen($input)." chars",$input);
				break;
				
			case is_resource($input):
				switch (get_resource_type($input)) {
					case "mysql result":
						return $this->parseInfo($key,get_resource_type($input).", ".mysql_num_rows($input)." rows",$input);
						break;
						
					case "mysql link":
						return $this->parseInfo($key,get_resource_type($input).", ".mysql_info($input),$input);
						break;
					
					default:
						return $this->parseInfo($key,gettype($input).", ".strlen($input)." chars",$input);
						break;
				}
				break;
				
			default:
				return $this->parseInfo($key,gettype($input),$input);
				break;
		}
	}
	
	public function parseInfo($key,$type,$value="",$info=""){
		$param["type"]=$type;
		$param["key"]=$key;
		$param["info"]=$info;
		$param["value"]=$value;
		return $this->parse("value",$param);
	}
	
	public function parseLi($a,$sub,$title="",$class=""){
		$param["class:li"]=$class;
		$param["value:a"]=$a;
		$param["value:title"]=$title;
		$param["sub"]=$sub;
		return $this->parse("li",$param);
	}
	
	public function parseText($value,$class=""){
		$param["class:li"]=$class;
		$param["value:li"]="<pre>".htmlspecialchars($value)."</pre>";
		return $this->parse("text",$param);
	}
	
	public function parse($element,$param)
	{
		$element=$this->template[$element];
		foreach ($param as $key => $value) {
			$key=$key ? $key : gettype($key);
			$element=str_replace("{".$key."}",$value,$element);
		}
		$element=$this->cleanup($element);
		return $element;
	}
	
	public function parseMysqlTable($result)
	{
		while($array=mysql_fetch_assoc($result)){
			$data[]=$array;
		}
		return $this->parseTable($data,$header);
	}
	
	public function parseTable($input,$header=false)
	{
		$head=true;
		$count=0;
		foreach($input as $array){
			$row="";
			$param="";
			$param["value:th"]=$count++;
			$row.=$this->parse("table:head:item",$param);
			
			if($head){
				$head=false;
				$param="";
				$param["value:th"]="";
				$headRow.=$this->parse("table:head:item",$param);
				foreach ($array as $key => $value) {
					$param="";
					$param["value:th"]=$key;
					$headRow.=$this->parse("table:head:item",$param);
				}
				$param="";
				$param["value:tr"]=$headRow;
				$return.=$this->parse("table:row:even",$param);
			}
			
			foreach ($array as $key => $value) {
				$param="";
				$param["value:td"]=$value;
				$row.=$this->parse("table:item",$param);
			}
			$param="";
			$param["value:tr"]=$row;
			
			if($switch){
				$switch=false;
				$return.=$this->parse("table:row:odd",$param);
			}else{
				$switch=true;
				$return.=$this->parse("table:row:even",$param);
			}
		}
		$param=array(
			"value:table"=>$return
		);
		$return = $this->parse("table",$param);
		return $return;
	}
	
	public function cleanup($input)
	{
		return preg_replace("/\{[^}]+}/","",$input);
	}
	
	public function print_styled()
	{
		echo $this->return;
	}
	
	public function save($filename)
	{
			if(!defined("dump".$filename)){
				$this->StyleAndJS(true);
				define("dump".$filename,true);
			}
			
			if(defined("dumpSave".$filename))
		    {
		    	file_put_contents($filename,$this->return,FILE_APPEND);
		    }else{
		    	file_put_contents($filename,$this->return);
		    	define("dumpSave".$filename,true);
		    }
		    
		    return '<a href="'.$filename.'">'.$filename.'</a>';
		
	}
}
?>